import os
import json
from LogUtils import logger
import threading
from PIL import Image, ImageTk
import ImageUtils
import shutil
import VocXml as XmlUtils


def check_Image_is_tag(image_path):
    """
    检查该图片的标注文件是否存在
    :param image_path:
    :return:
    """
    xmlPath = image_path.split(".")[0] + ".xml"
    return os.path.exists(xmlPath)


initJson = {"classList": [
    {"class": "other", "weight": 1, "color": "#25CCF7"},
    {"class": "ebike", "weight": 16, "color": "#FC427B"},
    {"class": "ebike_head", "weight": 8, "color": "#55E6C1"},
    {"class": "ebike_tail", "weight": 8, "color": "#EAB543"},
    {"class": "ebike_light", "weight": 8, "color": "#D6A2E8"},
    {"class": "windshield", "weight": 4, "color": "#ff3f34"},
    {"class": "bike", "weight": 16, "color": "#FDA7DF"},
    {"class": "raincoat", "weight": 4, "color": "#0652DD"},
    {"class": "babybike", "weight": 8, "color": "#EA2027"},
    {"class": "babycarry", "weight": 8, "color": "#C4E538"},
    {"class": "wheelchair", "weight": 8, "color": "#0652DD"},
    {"class": "gastank", "weight": 16, "color": "#006266"},
    {"class": "gastank_upper", "weight": 8, "color": "#EE5A24"},
    {"class": "bucket", "weight": 4, "color": "#9980FA"},
    {"class": "person", "weight": 1, "color": "#5758BB"},
    {"class": "hat", "weight": 2, "color": "#B53471"},
    {"class": "bag", "weight": 2, "color": "#1289A7"}
],
    "isAllowDeleteImage": False}  # 是否允许删除图片


def getClassListFromJson(json):
    L = []
    for item in json:
        L.append(json["class"])
    return L


class ImageSet:

    def __init__(self, rootPath):
        self.rootPath = rootPath
        self.__isAllowDeleteImage = False  # 是否允许删除图片
        self.__imagePathList = ImageUtils.getSpecifiedTypeFileFromDirectory(self.rootPath,
                                                                            [".jpg", ".png", ".jpeg"])  # 获取到了图片列表
        self.sortImagePathList()
        self.__xmlPathList = ImageUtils.getSpecifiedTypeFileFromDirectory(self.rootPath, [".xml"])  # 获取到了xml列表，可能为空
        self.__currentImageIndex = len(self.__xmlPathList)  ##定位到当前xml的位置
        ## 类型标签
        self.__classNameAndWeightColorList = self.__initConfigFile()  # 读取配置文件[ {"class": "gastank_upper", "weight": 8},{"class": "bucket", "weight": 4},]
        self.__currentClassIndex = len(self.__classNameAndWeightColorList) - 1  ##预定当前类别索引
        self.__classAndColor = {}
        self.initClassAndColor(self.__classNameAndWeightColorList)
        # threading.Thread(target=self.regularPictureThreadFun).start() # 用于提高速度

    def sortImagePathList(self):
        self.__imagePathList.sort()
        pass

    def initClassAndColor(self, configInfo):
        for item in configInfo:
            self.__classAndColor[item["class"]] = item["color"]
        pass

    def getColorFromAll(self):
        res = []
        for item in self.__classNameAndWeightColorList:
            res.append(item["color"])
        return res

    def getColorFromClass(self, clazz):
        return self.__classAndColor[clazz]

    def getClassAndWeightAndColorList(self):
        return self.__classNameAndWeightColorList

    def getIsAllowDeleteImage(self):
        return self.__isAllowDeleteImage

    def regularPictureThreadFun(self):
        """
        线程内提前修改图片大小
        :return:
        """
        for item in self.get_Image_Path_List():
            originImage = Image.open(item)
            length = max(originImage.size[0], originImage.size[1])
            if originImage.size[0] != originImage.size[1]:
                # 如果图片不是正方形的
                changeImage = Image.new('RGB', (length, length), (0, 0, 0))
                changeImage.paste(originImage,
                                  (int((length - originImage.size[0]) / 2), int((length - originImage.size[1]) / 2)))
                changeImage.save(item)

    def __initConfigFile(self):
        '''
        创建或者读取配置文件
        :param path: 父路径
        :return: [ {"class": "gastank_upper", "weight": 8},{"class": "bucket", "weight": 4},]
        '''
        filepath = self.rootPath + "/.ImageSet.json"
        if os.path.exists(filepath):  # 如果文件存在
            file = open(filepath, "r")
            root = json.load(file)
            print(root)

            if len(root["classList"]) <= 0 or "color" not in root["classList"][
                0]:  # 如果classList中没有color这个key，就是老版本，需要重新写入类型
                file.close()
                file = open(filepath, "w")
                json.dump(initJson, file)  # 把新版的initJson写入文件
                file.close()
                return initJson["classList"]
            else:  # 如果文件是新版的文件
                if "isAllowDeleteImage" in root:
                    self.__isAllowDeleteImage = root["isAllowDeleteImage"]
                print("是否允许删除图片" + str(self.__isAllowDeleteImage))
                return root["classList"]
        else:  # 如果文件不存在
            with open(filepath, "w") as file:
                json.dump(initJson, file)
            return initJson["classList"]

    # =================Image========================================
    def check_current_image_is_tag(self):
        """
        检查当前图片是否有标注文件
        :return:
        """
        return check_Image_is_tag(self.getCurrent_Image_Path())

    def get_Image_Path_List(self):
        return self.__imagePathList

    def get_Image_Name_List(self):
        """
        获取图片名列表，仅图片名不带后缀
        :return:
        """
        L = []
        for path in self.__imagePathList:
            base = os.path.basename(path)
            fileName = os.path.splitext(base)[0]
            L.append(fileName)
        return L

    def getCurrent_Image_Path(self):
        """
        获取当前图片路径
        :return:
        """
        return self.__imagePathList[self.__currentImageIndex]

    def getCurrent_Image_Name(self):
        return self.get_Image_Name_List()[self.__currentImageIndex]

    def get_The_Labeled_Image(self):
        """
        获取所有已经标注的图片路径
        :return:
        """
        L = []
        for (index, item) in enumerate(self.__imagePathList):
            xmlPath = item.split(".")[0] + ".xml"
            if xmlPath in self.__xmlPathList:
                L.append(item)
        return L

    # =================xml==========================================

    def get_Xml_Path_List(self):
        return self.__xmlPathList

    def getCurrent_Xml_Path_List(self):
        return self.__xmlPathList[self.__currentImageIndex]

    def add_Xml_Path_To_List(self, path):
        """
        添加xml文件的路径到xml的集合中
        :param path:
        :return:
        """
        if path not in self.__xmlPathList:
            self.__xmlPathList.append(path)

    def locationImage(self):
        """
        定位到最近的未标注的图片
        :return:
        """
        for (index, item) in enumerate(self.__imagePathList):
            xmlPath = item.split(".")[0] + ".xml"
            if xmlPath not in self.__xmlPathList:
                self.__currentImageIndex = index
                return

    # =================class========================================

    def get_Class_Name_List(self):
        """
        获取类型列表
        :return:
        """
        L = []
        for item in self.__classNameAndWeightColorList:
            L.append(item["class"])
        return L

    def check_Class_Name_Exist(self, className):
        """
        检查图片名是否已经存在队列
        :param className:
        :return:
        """
        return className in self.get_Class_Name_List()

    def add_Class_Name_To_Profile(self, className, weight, color):
        """
        添加类型
        :param className:
        :return:
        """
        # 添加到classList中
        self.__classNameAndWeightColorList.append({"class": className, "weight": weight, "color": color})
        filepath = self.rootPath + "/.ImageSet.json"
        with open(filepath, "w") as file:
            # 写入配置文件
            json.dump(
                {"classList": self.__classNameAndWeightColorList, "isAllowDeleteImage": self.__isAllowDeleteImage},
                file)
        self.__currentClassIndex = len(self.__classNameAndWeightColorList) - 1

    def delete_Class_Name_To_Profile(self, index):
        """
        删除类型
        :param className:
        :return:
        """
        self.__classNameAndWeightColorList.pop(index)
        filepath = self.rootPath + "/.ImageSet.json"
        with open(filepath, "w") as file:
            # 写入配置文件
            json.dump(
                {"classList": self.__classNameAndWeightColorList, "isAllowDeleteImage": self.__isAllowDeleteImage},
                file)
        self.__currentClassIndex = len(self.__classNameAndWeightColorList) - 1

    # =================ClassIndex========================================
    def setCurrentClassIndex(self, index):
        self.__currentClassIndex = index

    def getCurrentClassIndex(self):
        return self.__currentClassIndex

    def getCurrentClassName(self):
        return self.__classNameAndWeightColorList[self.__currentClassIndex]["class"]

    # =================ImageIndex========================================
    def setCurrentImageIndex(self, index):
        self.__currentImageIndex = index

    def getCurrentImageIndex(self):
        if self.__currentImageIndex == len(self.get_Image_Path_List()):
            return self.__currentImageIndex - 1
        return self.__currentImageIndex

    def addCurrentImageIndex(self):
        self.__currentImageIndex = self.__currentImageIndex + 1
        if self.__currentImageIndex >= len(self.__imagePathList):
            self.__currentImageIndex = len(self.__imagePathList) - 1

    def reduceCurrentImageIndex(self):
        self.__currentImageIndex = self.__currentImageIndex - 1
        if self.__currentImageIndex <= 0:
            self.__currentImageIndex = 0

    # =================分类存储=============================================
    def createMap(self):
        """
        创建classNameAndWeightList对应的Map
        :return:
        """
        L = {}
        for item in self.__classNameAndWeightColorList:
            L[item["class"]] = item["weight"]
        return L

    def classificationSave(self, savePath):
        """
        分类存储，根据权重来分类
        :param savePath: 保存的目录
        :return:
        """
        # 检查当前未分配的图片
        classifiedImageName = ImageUtils.getFileNameNotSufFromDir(savePath, [".jpg", ".png", ".jpeg"])  # 已经分类的图片的名不带后缀
        classMap = self.createMap()  # 参考类型 类型和单位分
        for item in self.get_Image_Path_List():
            currentFileName = ImageUtils.getFileNameNotSufFromPath(item)
            if currentFileName in classifiedImageName:  # 如果当前图片已经被分类了，就跳过
                continue
            xmlPath = item.split(".")[0] + ".xml"  # 对应的xml路径
            if not os.path.exists(xmlPath):
                logger.error("照片{0}对应的xml文件不存".format(item))
                return
            tags = XmlUtils.readTagFromFile(xmlPath)  # 获取到这个xml文件的标注信息
            logger.debug("====>读取到{0}的标注信息为{1}".format(xmlPath, tags))
            resultMap = dict()
            for tag in tags:  # 获取其中一个标签的作用 {"name": nameText, "xmin": xminText, "ymin": yminText, "xmax": xmaxText, "ymax": ymaxText}
                target = tag["name"]  # 当前标签的类型
                if target not in resultMap:  # 当前标签不在结构标签中
                    resultMap[target] = 0
                resultMap[target] = resultMap[target] + classMap.get(target)  # 原始分累加
            # 出循环后得到resultMap中是权重分计算后的，需要取得最大权重分的类型
            if len(resultMap) > 0:  # 当结果中有内容才复制
                result = max(resultMap, key=resultMap.get)
                logger.debug("计算{0}的最大标注为{1}".format(xmlPath, result))
                resultPath = savePath + "/" + result
                ImageUtils.check_and_create_dir(resultPath)  # 创建目录
                shutil.copy(item, resultPath)
                shutil.copy(xmlPath, resultPath)
            else:
                resultPath = savePath + "/" + "empty"
                logger.debug("计算{0}是空标注".format(xmlPath))
                ImageUtils.check_and_create_dir(resultPath)  # 创建目录
                shutil.copy(item, resultPath)
                shutil.copy(xmlPath, resultPath)

            shutil.copy(self.rootPath + "/.ImageSet.json", savePath)


# =================工具函数========================================


# ===============测试用====================

def getImageNameList(imagePathList):
    L = []
    for path in imagePathList:
        base = os.path.basename(path)
        fileName = os.path.splitext(base)[0]
        L.append(fileName)
    return L


if __name__ == '__main__':
    pass

    # logger.debug(getSpecifiedTypeFileFromDirectory("/Users/shu/Downloads/案例", [".jpg", ".png"]))
